<template>
  <div class="tutorial-page">
    <div class="tutorial-header">
      <h1>Vue 指令</h1>
      <p>学习Vue内置指令和自定义指令的使用方法</p>
    </div>

    <div class="tutorial-content">
      <div class="section">
        <h2>Vue 指令简介</h2>
        <p>Vue 指令是以 v- 开头的特殊属性，它们将某些行为应用到 DOM 元素上。指令的职责是当其表达式的值改变时相应地更新 DOM。</p>
        
        <h3>指令的构成</h3>
        <pre><code class="language-html" v-pre>&lt;!-- 指令的基本语法 --&gt;
&lt;div v-directive:argument.modifier="value"&gt;&lt;/div&gt;

&lt;!-- 示例 --&gt;
&lt;input v-model.lazy="msg"&gt;
&lt;a v-bind:href="url"&gt;&lt;/a&gt;
&lt;button v-on:click="doThis"&gt;&lt;/button&gt;</code></pre>
      </div>

      <div class="section">
        <h2>内置指令</h2>
        
        <h3>v-text</h3>
        <p>更新元素的文本内容</p>
        <pre><code class="language-html" v-pre>&lt;span v-text="msg"&gt;&lt;/span&gt;
&lt;!-- 等价于 --&gt;
&lt;span&gt;{{ msg }}&lt;/span&gt;</code></pre>
        
        <h3>v-html</h3>
        <p>更新元素的 innerHTML</p>
        <pre><code class="language-html" v-pre>&lt;div v-html="htmlContent"&gt;&lt;/div&gt;</code></pre>
        <div class="warning">
          <strong>注意：</strong>在网站上动态渲染任意 HTML 是非常危险的，容易导致 XSS 攻击。只在可信内容上使用 v-html，永不用在用户提交的内容上。
        </div>
        
        <h3>v-show</h3>
        <p>根据表达式的真假值，切换元素的 display CSS 属性</p>
        <pre><code class="language-html" v-pre>&lt;div v-show="isVisible"&gt;Hello!&lt;/div&gt;</code></pre>
        
        <h3>v-if / v-else / v-else-if</h3>
        <p>根据表达式的真假值来条件性地渲染元素</p>
        <pre><code class="language-html" v-pre>&lt;div v-if="type === 'A'"&gt;A&lt;/div&gt;
&lt;div v-else-if="type === 'B'"&gt;B&lt;/div&gt;
&lt;div v-else&gt;Not A/B&lt;/div&gt;</code></pre>
        
        <h3>v-for</h3>
        <p>基于数组来渲染一个列表</p>
        <pre><code class="language-html" v-pre>&lt;!-- 遍历数组 --&gt;
&lt;li v-for="item in items" :key="item.id"&gt;
  {{ item.text }}
&lt;/li&gt;

&lt;!-- 遍历对象 --&gt;
&lt;li v-for="(value, key) in object"&gt;
  {{ key }}: {{ value }}
&lt;/li&gt;

&lt;!-- 带索引 --&gt;
&lt;li v-for="(item, index) in items" :key="item.id"&gt;
  {{ index }} - {{ item.text }}
&lt;/li&gt;</code></pre>
        
        <h3>v-model</h3>
        <p>在表单控件元素上创建双向数据绑定</p>
        <pre><code class="language-html" v-pre>&lt;!-- 文本 --&gt;
&lt;input v-model="message" placeholder="edit me"&gt;
&lt;p&gt;Message is: {{ message }}&lt;/p&gt;

&lt;!-- 多行文本 --&gt;
&lt;textarea v-model="message" placeholder="add multiple lines"&gt;&lt;/textarea&gt;

&lt;!-- 复选框 --&gt;
&lt;input type="checkbox" id="checkbox" v-model="checked"&gt;
&lt;label for="checkbox"&gt;{{ checked }}&lt;/label&gt;

&lt;!-- 单选按钮 --&gt;
&lt;div v-for="item in items" :key="item.id"&gt;
  &lt;input type="radio" :id="item.id" :value="item.value" v-model="picked"&gt;
  &lt;label :for="item.id"&gt;{{ item.text }}&lt;/label&gt;
&lt;/div&gt;

&lt;!-- 选择框 --&gt;
&lt;select v-model="selected"&gt;
  &lt;option disabled value=""&gt;请选择&lt;/option&gt;
  &lt;option v-for="option in options" :key="option.value" :value="option.value"&gt;
    {{ option.text }}
  &lt;/option&gt;
&lt;/select&gt;</code></pre>
        
        <h3>v-bind</h3>
        <p>动态地绑定一个或多个 attribute，或一个组件 prop 到表达式</p>
        <pre><code class="language-html" v-pre>&lt;!-- 绑定 attribute --&gt;
&lt;img v-bind:src="imageSrc"&gt;
&lt;!-- 简写 --&gt;
&lt;img :src="imageSrc"&gt;

&lt;!-- 绑定 class --&gt;
&lt;div :class="{ active: isActive }"&gt;&lt;/div&gt;
&lt;div :class="[activeClass, errorClass]"&gt;&lt;/div&gt;

&lt;!-- 绑定 style --&gt;
&lt;div :style="{ color: activeColor, fontSize: fontSize + 'px' }"&gt;&lt;/div&gt;</code></pre>
        
        <h3>v-on</h3>
        <p>绑定事件监听器</p>
        <pre><code class="language-html" v-pre>&lt;!-- 监听 DOM 事件 --&gt;
&lt;button v-on:click="doThis"&gt;&lt;/button&gt;
&lt;!-- 简写 --&gt;
&lt;button @click="doThis"&gt;&lt;/button&gt;

&lt;!-- 事件修饰符 --&gt;
&lt;!-- 阻止单击事件继续传播 --&gt;
&lt;a @click.stop="doThis"&gt;&lt;/a&gt;

&lt;!-- 提交事件不再重载页面 --&gt;
&lt;form @submit.prevent="onSubmit"&gt;&lt;/form&gt;

&lt;!-- 修饰符可以串联 --&gt;
&lt;a @click.stop.prevent="doThat"&gt;&lt;/a&gt;

&lt;!-- 只有修饰符 --&gt;
&lt;form @submit.prevent&gt;&lt;/form&gt;</code></pre>
        
        <h3>v-once</h3>
        <p>只渲染元素和组件一次</p>
        <pre><code class="language-html" v-pre>&lt;span v-once&gt;这个将不会改变: {{ msg }}&lt;/span&gt;</code></pre>
        
        <h3>v-pre</h3>
        <p>跳过这个元素和它的子元素的编译过程</p>
        <pre><code class="language-html" v-pre>&lt;span v-pre&gt;{{ 这些内容不会被编译 }}&lt;/span&gt;</code></pre>
        
        <h3>v-cloak</h3>
        <p>保持在元素上直到关联实例结束编译</p>
        <pre><code class="language-html" v-pre>&lt;div v-cloak&gt;
  {{ message }}
&lt;/div&gt;</code></pre>
        <pre><code class="language-css" v-pre>[v-cloak] {
  display: none;
}</code></pre>
      </div>

      <div class="section">
        <h2>自定义指令</h2>
        <p>除了核心功能默认内置的指令，Vue 也允许注册自定义指令</p>
        
        <h3>全局注册</h3>
        <pre><code class="language-javascript" v-pre>// main.js
const app = createApp({})

// 注册一个全局自定义指令 `v-focus`
app.directive('focus', {
  // 当被绑定的元素挂载到 DOM 中时……
  mounted(el) {
    // 聚焦元素
    el.focus()
  }
})</code></pre>
        
        <h3>局部注册</h3>
        <pre><code class="language-javascript" v-pre>export default {
  directives: {
    focus: {
      // 指令的定义
      mounted(el) {
        el.focus()
      }
    }
  }
}</code></pre>
        
        <h3>钩子函数</h3>
        <ul>
          <li><strong>created</strong>: 在绑定元素的 attribute 或事件监听器被应用之前调用</li>
          <li><strong>beforeMount</strong>: 当指令第一次绑定到元素并且在挂载父组件之前调用</li>
          <li><strong>mounted</strong>: 在绑定元素的父组件被挂载后调用</li>
          <li><strong>beforeUpdate</strong>: 在更新包含组件的 VNode 之前调用</li>
          <li><strong>updated</strong>: 在包含组件的 VNode 及其子组件更新后调用</li>
          <li><strong>beforeUnmount</strong>: 当指令与元素解除绑定且父组件卸载之前调用</li>
          <li><strong>unmounted</strong>: 当指令与元素解除绑定且父组件卸载之后调用</li>
        </ul>
        
        <h3>钩子函数参数</h3>
        <pre><code class="language-javascript" v-pre>app.directive('color', {
  mounted(el, binding) {
    // el: 指令绑定的元素
    // binding: 包含以下属性的对象
    //   - value: 传递给指令的值
    //   - oldValue: 指令的前一个值
    //   - arg: 传给指令的参数
    //   - modifiers: 包含修饰符的对象
    //   - instance: 使用该指令的组件实例
    //   - dir: 指令的定义对象
    
    el.style.color = binding.value
  }
})</code></pre>
        
        <h3>使用示例</h3>
        <pre><code class="language-html" v-pre>&lt;p v-color="'red'"&gt;红色文字&lt;/p&gt;
&lt;p v-color:background="'blue'"&gt;蓝色背景&lt;/p&gt;</code></pre>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref } from 'vue'

// 定义示例数据以避免渲染错误
const items = ref([
  { id: 1, text: '项目 1', value: 'value1' },
  { id: 2, text: '项目 2', value: 'value2' },
  { id: 3, text: '项目 3', value: 'value3' }
])

const object = ref({
  name: 'Vue',
  version: '3.0',
  framework: 'JavaScript'
})

const message = ref('Hello Vue!')
const htmlContent = ref('<strong>这是HTML内容</strong>')
const isVisible = ref(true)
const type = ref('A')
const imageSrc = ref('/src/assets/logo.svg')
const isActive = ref(true)
const activeClass = ref('active')
const errorClass = ref('error')
const activeColor = ref('red')
const fontSize = ref(16)
const checked = ref(false)
const picked = ref('value1')
const selected = ref('')
const options = ref([
  { value: 'option1', text: '选项 1' },
  { value: 'option2', text: '选项 2' },
  { value: 'option3', text: '选项 3' }
])
</script>

<style scoped>
@import '@/assets/tutorial-styles.css';

.warning {
  background-color: #fff3cd;
  border: 1px solid #ffeaa7;
  color: #856404;
  padding: 15px;
  border-radius: 5px;
  margin: 20px 0;
}

.warning strong {
  color: #856404;
}
</style>